﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Framework.Event;
using Microsoft.Practices.Unity;
using Framework.Config;

namespace Framework.Bus
{
    /// <summary>
    /// per request life time
    /// </summary>
    class EventBusImpl : IEventBus
    {
        #region Private Fields
        bool _Committed;
        /// <summary>
        /// Container life time
        /// </summary>

        ISyncBus<IDomainEvent> _SyncEventBus;
        /// <summary>
        /// Container life time
        /// </summary>

        IAsyncBus<IDomainEvent> _AsyncEventBus;

        protected readonly Queue<IDomainEvent> _MessageQueue;
        protected readonly object _QueueLock;

        #endregion

        public EventBusImpl([Dependency(Constants.Configuration.SyncDomainEventBus)]ISyncBus<IDomainEvent> syncEventBus
                          , [Dependency(Constants.Configuration.AsyncDomainEventBus)]IAsyncBus<IDomainEvent> asyncEventBus = null)
        {
            _Committed = false;
            _MessageQueue = new Queue<IDomainEvent>();
            _QueueLock = new object();
            _SyncEventBus = syncEventBus;
            _AsyncEventBus = asyncEventBus;
        }

        #region IBus<IDomainEvent> Members

        public void Commit()
        {
            if (_AsyncEventBus == null)
            {
                return;
            }
            lock (_QueueLock)
            {
                _AsyncEventBus.Publish(_MessageQueue);
                _MessageQueue.Clear();
                _Committed = true;
            }
        }

        public void Send(IDomainEvent @event)
        {
            throw new NotImplementedException();
        }

        public void Send(IEnumerable<IDomainEvent> events)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (!_Committed)
            {
                try
                {
                    this.Commit();
                }
                catch
                {
                    throw;
                }
            }
        }

        #endregion

        #region IBus<IDomainEvent> Members


        public void Publish(IDomainEvent @event)
        {
            _Committed = false;
            _SyncEventBus.Publish(@event);
            lock (_QueueLock)
            {
                _MessageQueue.Enqueue(@event);
            }
        }

        public void Publish(IEnumerable<IDomainEvent> events)
        {
            _Committed = false;
            _SyncEventBus.Publish(events);
            lock (_QueueLock)
            {
                foreach (var @event in events)
                {
                    _MessageQueue.Enqueue(@event);
                }
            }
        }

        #endregion
    }
}
